#include <Threading.h>
#include <ctime>
#include <iostream>
#include <fstream>
using namespace std;

int WindowsThreading::AssignMemory(int mat)
{
	if(mat == MATRIXA)	
		matrix_A = new int[rows_matrix_A*colums_matrix_A];
	else if(mat == MATRIXB)
		matrix_B = new int[rows_matrix_B*colums_matrix_B];
	else if(mat == MATRIXC)
		matrix_C = new int[rows_matrix_A*colums_matrix_B];
	else if(mat == MATRIXBTRANSPOSE)
		matrix_B_transpose = new int[colums_matrix_B*rows_matrix_B];
	else
		return -1;
	
	return 0;
}

int WindowsThreading::MatrixGeneration(int mat)
{
	srand(time(NULL));
	if(mat == MATRIXA)
	{
		for (int i = 0; i < rows_matrix_A * colums_matrix_A; i++)
			matrix_A[i] = rand() % 9;
	}
	else if(mat == MATRIXB)
	{
		for (int i = 0; i < rows_matrix_B * colums_matrix_B; i++)
			matrix_B[i] = rand() % 9;
	}
	else
		return -1;
	return 0;
}
/** function for taking transpose of B **/
int WindowsThreading::MatrixTranspose()
{
	for (int i=0; i<colums_matrix_B; i++)
		for (int j=0; j<rows_matrix_B; j++)
			matrix_B_transpose[i*rows_matrix_B+j] = matrix_B[j*colums_matrix_B+i];
	return 0;
}

int WindowsThreading::DeleteMemory(int mat)
{
	if(mat == MATRIXA)
		delete matrix_A;
	else if(mat == MATRIXB)
		delete matrix_B;
	else if(mat == MATRIXC)
		delete matrix_C;
	else if(mat == MATRIXBTRANSPOSE)
		delete matrix_B_transpose;
	else
		return -1;	
	return 0;
}
/** function for storing matrices in files **/
int WindowsThreading::MatrixStore(int mat)
{
	if(mat == MATRIXA)
	{
		ofstream matrix_A_write("matrix_A.txt");
		for (int i = 0; i < rows_matrix_A; i++)
		{
			for (int j = 0; j < colums_matrix_A; j++)
				matrix_A_write << matrix_A[j+i*colums_matrix_A]<< "   ";
			matrix_A_write << endl;
		}
		matrix_A_write.close();
	}
	else if(mat == MATRIXB)
	{
		ofstream matrix_B_write("matrix_B.txt");
		for (int i = 0; i < rows_matrix_B; i++)
		{
			for (int j = 0; j < colums_matrix_B; j++)
				matrix_B_write << matrix_B[i*colums_matrix_B+j]<< "   ";
			matrix_B_write << endl;
		}
		matrix_B_write.close();
	}
	else if(mat == MATRIXC)
	{
		ofstream matrix_C_write("matrix_C.txt");
		for (int i = 0; i < rows_matrix_A; i++)
		{
			for (int j = 0; j < colums_matrix_B; j++)
				matrix_C_write << matrix_C[i*colums_matrix_B+j]<< "   ";
			matrix_C_write << endl;
		}
		matrix_C_write.close();
	}
	else
		return -1;

	return 0;
}
/** Function for memory content copy **/
void* WindowsThreading::MemoryCopy (void *destination_ptr, const void *source_ptr, int int_size)
{
    char *destination_buffer = (char*)destination_ptr;
    char *Data = (char*)source_ptr;
    for(int i = 0; i <int_size; i++)
            destination_buffer[i] = Data[i];
    return destination_buffer;
}

/** global thread function **/
void ThreadFunction(void* ptr)
{
	DataForThreadFunc* obj_ptr;
	obj_ptr = (DataForThreadFunc*)ptr;
	int i,j,k,temp;
	for(i=(obj_ptr->current_object->rows_matrix_A*obj_ptr->thread_number)/obj_ptr->current_object->number_of_threads;i<(obj_ptr->current_object->rows_matrix_A*(obj_ptr->thread_number+1))/obj_ptr->current_object->number_of_threads;i++)
	{
		for(j=0; j<obj_ptr->current_object->colums_matrix_B; j++)
		{
			temp=0;
			for (k=0; k<obj_ptr->current_object->rows_matrix_B; k++)
				temp = temp + (obj_ptr->current_object->matrix_A[i*obj_ptr->current_object->colums_matrix_A+k] * obj_ptr->current_object->matrix_B_transpose[j*obj_ptr->current_object->rows_matrix_B+k]);
			obj_ptr->current_object->matrix_C[i*obj_ptr->current_object->colums_matrix_B+j]=temp;
		}
	}
}